/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_orm.htm
 *
 * Zhiqim Orm is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.orm.impl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import org.zhiqim.kernel.Global;
import org.zhiqim.kernel.MultiInstancer;
import org.zhiqim.kernel.annotation.AnNonnull;
import org.zhiqim.kernel.annotation.AnNullable;
import org.zhiqim.kernel.model.maps.HashMapCV;
import org.zhiqim.kernel.model.maps.HashMapSO;
import org.zhiqim.kernel.model.maps.HashMapSS;
import org.zhiqim.kernel.model.maps.MapSO;
import org.zhiqim.kernel.model.maps.MapSS;
import org.zhiqim.kernel.paging.PageBuilder;
import org.zhiqim.kernel.paging.PageResult;
import org.zhiqim.kernel.transaction.Transaction;
import org.zhiqim.kernel.transaction.TransactionManager;
import org.zhiqim.kernel.util.Classes;
import org.zhiqim.orm.ORM;
import org.zhiqim.orm.ORMConstants;
import org.zhiqim.orm.ORMException;
import org.zhiqim.orm.ORMServer;
import org.zhiqim.orm.ZSQL;
import org.zhiqim.orm.ZTable;
import org.zhiqim.orm.ZTabler;
import org.zhiqim.orm.annotation.AnIndex;
import org.zhiqim.orm.annotation.AnIndexValue;
import org.zhiqim.orm.annotation.AnTable;
import org.zhiqim.orm.annotation.AnTableField;
import org.zhiqim.orm.annotation.AnTableReplace;
import org.zhiqim.orm.cache.ZTableCache;
import org.zhiqim.orm.dbo.Batcher;
import org.zhiqim.orm.dbo.Dbo;
import org.zhiqim.orm.dbo.Selector;
import org.zhiqim.orm.dbo.Updater;
import org.zhiqim.orm.dbo.defined._Table;
import org.zhiqim.orm.dbo.defined._TableField;
import org.zhiqim.orm.exception.TableNotExistException;

/**
 * 标准类与数据库表映射调用，支持(truncate,exist,insert,replace,update,delete,count,sum,item,list,page)<br><br>
 * truncate,    清除表类对应的表<br>
 * exist,       检查表类对应的表是否存在<br>
 * create       创建表类对应的表
 * drop         删除表类对应的表
 * insert,      插入表类对应的表一条数据<br>
 * replace,     替换表类对应的表一条数据，根据主键<br>
 * update,      更新表类对应的表一条数据或根据条件更新数据<br>
 * delete,      删除表类对应的表一条数据或根据条件删除数据<br>
 * count,       统计表类对应的表数目<br>
 * sum,         总计表类对应的表数目<br>
 * item,        查询表类对应的表一条数据，根据主键，或根据条件排序取第一条<br>
 * list,        查询表类对应的表列表，或根据条件排序<br>
 * pag,         分页查询表类对应的表列表，指定分页页码和页数目<br>
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 * @version v1.2.0 @author zouzhigang 2016-6-27 修改原类名ZTableExcutor为ZTableExecutor，正式使用表类名称
 */
public final class ZTableImplement extends MultiInstancer implements ZTable, ORMConstants
{
    private ORMServer server;
    private ZSQL zSQL;
    private ZTabler zTabler;
    private ZTableCache zCache;
    private HashMapCV<_Table> tableMap;
    
    public ZTableImplement(ORMServer server)
    {
        this.server = server;
        this.zSQL = server.sql();
        this.zTabler = server.tabler();
        this.zCache = new ZTableCache(server);
        this.tableMap = new HashMapCV<>(true);
    }
    
    /**
     * 通过表类获取表对象
     * 
     * @param cls     表类
     * @return          表对象
     */
    public _Table getTable(Class<?> cls)
    {
        _Table _table = tableMap.get(cls);
        if (_table != null)
            return _table;
        
        AnTable anTable = cls.getAnnotation(AnTable.class);
        if (anTable == null)
            return null;
        
        _table = new _Table(cls.getName(), anTable.table(), anTable.key(), anTable.type());
        //1.增加索引
        AnIndex anIndex = cls.getAnnotation(AnIndex.class);
        if (anIndex != null)
        {
            AnIndexValue[] values = anIndex.value();
            for (AnIndexValue value : values)
            {
                _table.addIndex(value.name(), value.column(), value.unique());
            }
        }
        //2.增加字段和可替换字段
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields)
        {
            String fieldName = field.getName();
            AnTableField f = field.getAnnotation(AnTableField.class);
            if (f != null)
            {
                _table.addField(fieldName, f.column(), f.type(), f.notNull());
            }
            
            AnTableReplace r = field.getAnnotation(AnTableReplace.class);
            if (r != null)
            {
                _table.addReplace(fieldName, r.value());
            }
        }
        
        //3.放置到缓存
        tableMap.put(cls, _table);
        return _table;
    }
    
    /**
     * 通过表名获取表对象
     * 
     * @param tableName     表名
     * @return              表对象
     */
    public _Table getTableByTableName(String tableName)
    {
        for(_Table _table : tableMap.values())
        {
            if (tableName.equals(_table.getTable()))
                return _table;
        }
        
        //未找到则从全局找
        Collection<Class<?>> list = Global.getClassList();
        for (Class<?> clazz : list)
        {
            if (!clazz.isAnnotationPresent(AnTable.class))
                continue;
            
            _Table _table = getTable(clazz);
            if (tableName.equals(_table.getTable()))
                return _table;
        }
        
        return null;
    }
    
    /********************************************************************************************/
    //cache 表缓存
    /********************************************************************************************/
    
    /** 更新数据缓存任务安排 */
    public void schedule()
    {
        zCache.schedule();
    }
    
    /**
     * 更新数据到缓存
     * 
     * @param cls           表类
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public <T> void cache(Class<T> cls) throws ORMException, SQLException
    {
        if (!server.isCache(cls))
        {//未配置缓存的不处理
            return;
        }
        
        _Table _table = getTable(cls);
        if (_table == null)
            throw new ORMException("ZTable[cache]["+cls.getName()+"][未找到相应的配置]");
        
        //创建表当不存在时
        zTabler.create(_table);
        
        //组装SQL
        StringBuilder sql = new StringBuilder("select * from ").append(_table.getTable());
        
        List<T> list = null;
        try
        {//执行SQL
            list = zSQL.executeQuery(sql.toString(), cls);
        }
        catch (TableNotExistException e) 
        {//表不存在重作一次（可能被管理员删除，对误操作增加的保险机制）
            zTabler.create(_table, true);
            list = zSQL.executeQuery(sql.toString(), cls);
        }
        
        //刷新到缓存
        zCache.cache(cls, list);
    }
    
    /**
     * 获取缓存原生数据，建议仅用于性能要求苛刻的时候，警告：不允许对列表作增删改操作，以及对每条数据作修改
     * 
     * @param cls           表类
     * @return              缓存原始数据
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    @AnNonnull               //未查到数据为空列表
    public <T> List<T> cacheListRaw(Class<T> cls) throws ORMException, SQLException
    {
        if (!server.isCache(cls))
            throw new ORMException("ZTable[cacheListRaw]["+cls.getName()+"][不支持缓存]");
        
        return zCache.listRaw(cls);
    }
    
    /**
     * 获取缓存原生数据列表，警告：不允许对列表作增删改操作，以及对每条数据作修改
     * 
     * @param cls           表类
     * @param selector      对象查询器
     * @return              返回表对象列表
     * @throws ORMException 映射异常,如果传入的属性不在配置文件中则异常
     * @throws SQLException 数据库异常
     */
    @AnNonnull               //未查到数据为空列表
    public <T> List<T> cacheListRaw(Class<T> cls, Selector selector) throws ORMException, SQLException
    {
        if (!server.isCache(cls))
            throw new ORMException("ZTable[cacheListRaw]["+cls.getName()+"][不支持缓存]");
        
        return zCache.listRaw(cls, selector);
    }
    
    /**
     * 通过主键获取缓存原生一条数据，警告：不允许数据作修改
     * 
     * @param cls           表类
     * @param ids           表主键
     * @return              缓存原始数据
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    @AnNullable              //根据主键没查到数据情况
    public <T> T cacheItemRaw(Class<T> cls, Object... ids) throws ORMException, SQLException
    {
        if (!server.isCache(cls))
            throw new ORMException("ZTable[cacheItemRaw]["+cls.getName()+"][不支持缓存]");
        
        return zCache.item(cls, ids);
    }
    
    /********************************************************************************************/
    //batch 表批处理
    /********************************************************************************************/
    
    /**
     * 批量处理插入/更新/删除数据
     * 
     * @param batcherList   批量表
     * @return              响应表
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int[] batch(List<Batcher> batcherList) throws ORMException, SQLException
    {
        if (batcherList == null || batcherList.isEmpty())
            return new int[0];
        
        Transaction tx = null;
        int[] rets = new int[batcherList.size()];
        
        try
        {
            tx = TransactionManager.beginTransaction(server.getId());
            
            int i=0;
            for (Batcher batcher : batcherList)
            {//使用foreach而不使用fori是但心LinkedList
                switch (batcher.getType())
                {
                case INSERT:
                    rets[i++] = insert(batcher.getInsertData(), batcher.getInsertReplaceMap());
                    break;
                case REPLACE:
                    rets[i++] = replace(batcher.getReplaceData(), batcher.getReplaceReplaceMap());
                    break;
                case INSERT_OR_UPDATE:
                    rets[i++] = insertOrUpdate(batcher.getInsertOrUpdateData(), batcher.getInsertOrUpdateUpdater());
                    break;
                case UPDATE:
                    rets[i++] = update(batcher.getUpdateData(), batcher.getUpdateReplaceMap());
                    break;
                case UPDATER:
                    rets[i++] = update(batcher.getUpdaterClass(), batcher.getUpdaterUpdater());
                    break;
                case DELETE_ID:
                    rets[i++] = delete(batcher.getDeleteClass(), batcher.getDeleteReplaceMap(), batcher.getDeleteIds());
                    break;
                case DELETE_SELECTOR:
                    rets[i++] = delete(batcher.getDeleteClass(), batcher.getDeleteSelector());
                    break;
                }
            }
            
            tx.commit();
        }
        catch(ORMException | SQLException e)
        {
            if (tx != null)
            {
                try{tx.rollback();}catch(Exception e2){}
            }
            
            throw e;
        }
        catch(Exception e)
        {
            if (tx != null)
            {
                try{tx.rollback();}catch(Exception e2){}
            }
            
            throw new ORMException(e);
        }
        finally
        {
            if (tx != null)
            {
                try{tx.close();}catch(Exception e){}
            }
        }
        
        return rets;
    }
    
    /********************************************************************************************/
    //truncate 清空表
    /********************************************************************************************/
    
    /**
     * 清空[表类]对应的[实际表]
     * 
     * @param cls           表类
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public void truncate(Class<?> cls) throws ORMException, SQLException
    {
        truncate(cls, new HashMapSS());
    }
    
    /**
     * 清空[表类]对应的[实际表]分表，支持表名中替换字段指定为$ID$，如LOG_TRACE$ID$
     * 
     * @param clazz         表类
     * @param id            分表编号
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public void truncate(Class<?> cls, String id) throws ORMException, SQLException
    {
        truncate(cls, new HashMapSS(_ID_, id));
    }
    
    /**
     * 清空[表类]对应的[实际表]，支持表名中有多个替换字段，如LOG_TRACE_$MONTH$_$ID$
     * 
     * @param cls           表类
     * @param replaceMap    替换表
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public void truncate(Class<?> cls, MapSS replaceMap) throws ORMException, SQLException
    {
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[truncate]["+cls.getName()+"][未找到相应的配置]");
        
        zTabler.truncate(_table, replaceMap);
        
        if (server.isCache(cls))
        {//更新缓存
            cache(cls);
        }
    }
    
    /********************************************************************************************/
    //exist 表是否存在
    /********************************************************************************************/
    
    /**
     * 是否存在[表类]对应的[实际表]
     * 
     * @param cls           表类
     * @return              =true表示存在，=false表示不存在
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public boolean exist(Class<?> cls) throws ORMException, SQLException
    {
        return zTabler.exist(getTable(cls));
    }

    /**
     * 是否存在[表类]对应的[实际表]分表，支持表名中替换字段指定为$ID$，如LOG_TRACE$ID$
     * 
     * @param cls           表类
     * @param id            分表编号
     * @return              =true表示存在，=false表示不存在
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public boolean exist(Class<?> cls, String id) throws ORMException, SQLException
    {
        return zTabler.exist(getTable(cls), new HashMapSS(_ID_, id));
    }
    
    /**
     * 是否存在[表类]对应的[实际表]可替换表，支持表名中有多个替换字段，如LOG_TRACE_$MONTH$_$ID$
     * 
     * @param cls           表类
     * @param replaceMap    可替换字段表
     * @return              =true表示存在，=false表示不存在
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public boolean exist(Class<?> cls, MapSS replaceMap) throws ORMException, SQLException
    {
        return zTabler.exist(getTable(cls), replaceMap);
    }
    
    /********************************************************************************************/
    //create 创建表
    /********************************************************************************************/
    
    /**
     * 创建[表类]对应的[实际表]
     * 
     * @param cls           表类
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public void create(Class<?> cls) throws ORMException, SQLException
    {
        zTabler.create(getTable(cls));
    }
    
    /**
     * 创建[表类]对应的[实际表]分表
     * 
     * @param cls           表类
     * @param id            分表编号
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public void create(Class<?> cls, String id) throws ORMException, SQLException
    {
        zTabler.create(getTable(cls), new HashMapSS(_ID_, id));
    }
    
    /**
     * 创建[表类]对应的[实际表]可替换表，支持表名中有多个替换字段，如LOG_TRACE_$MONTH$_$ID$
     * 
     * @param cls           表类
     * @param replaceMap    可替换字段表
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public void create(Class<?> cls, MapSS replaceMap) throws ORMException, SQLException
    {
        zTabler.create(getTable(cls), replaceMap);
    }
    
    /********************************************************************************************/
    //drop 删除表
    /********************************************************************************************/
    
    /**
     * 创建[表类]对应的[实际表]
     * 
     * @param clazz         表类
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public void drop(Class<?> cls) throws ORMException, SQLException
    {
        zTabler.drop(getTable(cls));
    }
    
    /**
     * 创建[表类]对应的[实际表]分表
     * 
     * @param cls           表类
     * @param id            分表编号
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public void drop(Class<?> cls, String id) throws ORMException, SQLException
    {
        zTabler.drop(getTable(cls), new HashMapSS(_ID_, id));
    }
    
    /**
     * 创建[表类]对应的[实际表]可替换表，支持表名中有多个替换字段，如LOG_TRACE_$MONTH$_$ID$
     * 
     * @param cls           表类
     * @param replaceMap    可替换字段表
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public void drop(Class<?> cls, MapSS replaceMap) throws ORMException, SQLException
    {
        zTabler.drop(getTable(cls), replaceMap);
    }
    
    /********************************************************************************************/
    //insert 插入数据
    /********************************************************************************************/
    
    /**
     * 增加数据,传入标准[表类]对象
     * 
     * @param data          表对象
     * @return int          表示插入的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int insert(Object data) throws ORMException, SQLException
    {
        return insert(data, null);
    }
    
    /**
     * 增加数据，支持表或字段中中有多个替换字段，如LOG_TRACE_$MONTH$_$ID$
     * 
     * @param data          表对象
     * @param replaceMap    适配表
     * @return              int 表示插入的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int insert(Object data, MapSS replaceMap) throws ORMException, SQLException
    {
        Class<?> cls = data.getClass();
        _Table _table = getTable(data.getClass());
        ORM.as(_table != null?null:"ZTable[insert]["+cls.getName()+"][未找到相应的配置]");
        
        //检查和尝试创建表
        _table.addReplaceToMap(data, replaceMap);
        zTabler.create(_table, replaceMap);
        
        //组装SQL
        String sql = zTabler.toInsertOrReplaceSQL(_table, "insert");
        
        int ret = 0;
        try
        {//执行SQL
            ret = zSQL.executeUpdate(sql, data, replaceMap);
        }
        catch (TableNotExistException e) 
        {//表不存在重作一次（可能被管理员删除，对误操作增加的保险机制）
            zTabler.create(_table, replaceMap, true);
            ret = zSQL.executeUpdate(sql, data, replaceMap);
        }
        
        if (ret > 0 && server.isCache(cls))
        {//更新缓存
            cache(cls);
        }
        
        return ret;
    }
    
    /**
     * 替换数据,传入标准[表类]对象和更新器（取fieldMap和replaceMap）当存在时指定修改的值
     * 
     * @param data          表对象
     * @param updater       更新器
     * @return              int 表示插入的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int insertOrUpdate(Object data, Updater updater) throws ORMException, SQLException
    {
        Class<?> cls = data.getClass();
        _Table _table = getTable(data.getClass());
        ORM.as(_table != null?null:"ZTable[insertOrUpdate]["+cls.getName()+"][未找到相应的配置]");
        
        if (!server.isMysql())
            throw new ORMException("ZTable[insertOrUpdate]不支持当前数据库类型]");
        
        //检查和尝试创建表
        _table.addReplaceToMap(data, updater.getReplaceMap());
        zTabler.create(_table, updater.getReplaceMap());
        
        //组装字段和条件SQL和参数列
        MapSO paramMap = new HashMapSO();
        String insertSQL = toInsertOrUpdateSQL(_table, data, paramMap);
        String updateSQL = zTabler.toUpdateFieldSQL(_table, updater, paramMap);
        
        //组装SQL
        StringBuilder sql = new StringBuilder(insertSQL).append(" on duplicate key update ").append(updateSQL);
        
        int ret = 0;
        try
        {//执行SQL
            ret = zSQL.executeUpdate(sql.toString(), paramMap, updater.getReplaceMap());
        }
        catch (TableNotExistException e) 
        {//表不存在重作一次（可能被管理员删除，对误操作增加的保险机制）
            zTabler.create(_table, updater.getReplaceMap(), true);
            ret = zSQL.executeUpdate(sql.toString(), paramMap, updater.getReplaceMap());
        }
        
        if (ret > 0 && server.isCache(cls))
        {//更新缓存
            cache(cls);
        }
        
        return ret;
    }
    
    /**
     * 批量增加数据
     * 
     * @param dataList      表对象列表
     * @return              int 表示插入的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int[] insertBatch(List<?> dataList) throws ORMException, SQLException
    {
        return insertBatch(dataList, null);
    }
    
    /**
     * 批量增加数据，支持表或字段中中有多个替换字段，如LOG_TRACE_$MONTH$_$ID$
     * 
     * @param dataList      表对象列表
     * @param replaceMap    适配表
     * @return              int 表示插入的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int[] insertBatch(List<?> dataList, MapSS replaceMap) throws ORMException, SQLException
    {
        if (dataList == null || dataList.isEmpty())
            return new int[0];
        
        Class<?> cls = dataList.get(0).getClass();
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[insertBatch]["+cls.getName()+"][未找到相应的配置]");
        
        //检查和尝试创建表
        _table.addReplaceToMap(dataList.get(0), replaceMap);
        zTabler.create(_table, replaceMap);
        
        //组装SQL
        String sql = zTabler.toInsertOrReplaceSQL(_table, "insert");
        
        int[] rets = null;
        try
        {//执行SQL
            rets = zSQL.executeBatch(sql, dataList, replaceMap);
        }
        catch (TableNotExistException e) 
        {//表不存在重作一次（可能被管理员删除，对误操作增加的保险机制）
            zTabler.create(_table, replaceMap, true);
            rets = zSQL.executeBatch(sql, dataList, replaceMap);
        }
        
        if (server.isCache(cls) && hasDataUpdate(rets))
        {//更新缓存
            cache(cls);
        }
        
        return rets;
    }
    
    /********************************************************************************************/
    //replace 替换数据，MYSQL支持，如果有数据先删除后增加
    /********************************************************************************************/
    
    /**
     * 替换数据,传入标准[表类]对象
     * 
     * @param data          表对象
     * @return              int 表示插入的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int replace(Object data) throws ORMException, SQLException
    {
        return replace(data, null);
    }
    
    /**
     * 替换数据，支持表或字段中中有多个替换字段，如LOG_TRACE_$MONTH$_$ID$
     * 
     * @param data          表对象
     * @param replaceMap    适配表
     * @return              int 表示插入的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int replace(Object data, MapSS replaceMap) throws ORMException, SQLException
    {
        Class<?> cls = data.getClass();
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[replace]["+cls.getName()+"][未找到相应的配置]");
        
        if (!server.isMysql() && !server.isSqlite())
        {
            String[] fields = _table.getKeyFieldArr();
            Object[] values = new Object[fields.length];
            for (int i=0;i<fields.length;i++)
            {
                values[i] = Classes.getFieldValue(data, fields[i]);
            }
            
            delete(cls, replaceMap, values);
            return insert(data, replaceMap);
        }
        
        //检查和尝试创建表
        _table.addReplaceToMap(data, replaceMap);
        zTabler.create(_table, replaceMap);
        
        //组装SQL
        String sql = zTabler.toInsertOrReplaceSQL(_table, "replace");
        
        int ret = 0;
        try
        {//执行SQL
            ret = zSQL.executeUpdate(sql, data, replaceMap);
        }
        catch (TableNotExistException e) 
        {//表不存在重作一次（可能被管理员删除，对误操作增加的保险机制）
            zTabler.create(_table, replaceMap, true);
            ret = zSQL.executeUpdate(sql, data, replaceMap);
        }
        
        if (ret > 0 && server.isCache(cls))
        {//更新缓存
            cache(cls);
        }
        
        return ret;
    }
    
    /**
     * 批量替换数据
     * 
     * @param dataList      表对象列表
     * @return              int 表示插入的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int[] replaceBatch(List<?> dataList) throws ORMException, SQLException
    {
        return replaceBatch(dataList, null);
    }
    
    /**
     * 批量替换数据，支持表或字段中中有多个替换字段，如LOG_TRACE_$MONTH$_$ID$
     * 
     * @param dataList      表对象列表
     * @param replaceMap    适配表
     * @return              int 表示插入的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int[] replaceBatch(List<?> dataList, MapSS replaceMap) throws ORMException, SQLException
    {
        if (dataList == null || dataList.isEmpty())
            return new int[0];
        
        Class<?> cls = dataList.get(0).getClass();
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[replaceBatch]["+cls.getName()+"][未找到相应的配置]");
        
        if (!server.isMysql() && !server.isSqlite())
            throw new ORMException("ZTable[replaceBatch]不支持当前数据库类型]");
        
        //检查和尝试创建表
        _table.addReplaceToMap(dataList.get(0), replaceMap);
        zTabler.create(_table, replaceMap);
        
        //组装SQL
        String sql = zTabler.toInsertOrReplaceSQL(_table, "replace");
        
        int[] rets = null;
        try
        {//执行SQL
            rets = zSQL.executeBatch(sql, dataList, replaceMap);
        }
        catch (TableNotExistException e) 
        {//表不存在重作一次（可能被管理员删除，对误操作增加的保险机制）
            zTabler.create(_table, replaceMap, true);
            rets = zSQL.executeBatch(sql, dataList, replaceMap);
        }
        
        if (server.isCache(cls))
        {//更新缓存
            cache(cls);
        }
        
        return rets;
    }
    
    /********************************************************************************************/
    //update 更新数据
    /********************************************************************************************/
    
    /**
     * 更新数据，指定更新器需要更新的字段、条件和可替换表
     * 
     * @param cls           表类
     * @param updater       更新器
     * @return              int 表示更新的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int update(Class<?> cls, Updater updater) throws ORMException, SQLException
    {
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[update]["+cls.getName()+"][未找到相应的配置]");
        
        String result = _table.isValidUpdater(updater);
        if (result != null)
            throw new ORMException("ZTable[update]["+cls.getName()+"][更新器字段["+result+"]类型和值要求不一致]");
        
        int ret = zTabler.update(_table, updater);
        
        if (ret > 0 && server.isCache(cls))
        {//更新缓存
            cache(cls);
        }
        
        return ret;
    }
    
    /**
     * 更新数据，指定对象，根据主键进行更新，主键值不更新
     * 
     * @param data          表对象
     * @return              int 表示更新的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int update(Object data) throws ORMException, SQLException
    {
        return update(data, null);
    }
    
    /**
     * 更新数据，指定对象，根据主键进行更新，主键值不更新，支持可替换表
     * 
     * @param data          表对象
     * @param replaceMap    适配表
     * @return              int 表示更新的条数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int update(Object data, MapSS replaceMap) throws ORMException, SQLException
    {
        Class<?> cls = data.getClass();
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[update]["+cls.getName()+"][未找到相应的配置]");
        ORM.as(!_table.isAllKey()?null:"ZTable[update]["+cls.getName()+"][所有字段都是关键属性,不支持此更新方法");
        
        //检查和尝试创建表
        _table.addReplaceToMap(data, replaceMap);
        zTabler.create(_table, replaceMap);
        
        //组装SQL
        StringBuilder sql = new StringBuilder("update ").append(_table.getTable()).append(" set ");
        //field
        List<_TableField> fieldList = _table.getFieldListNoKey();
        //第一个不加逗号
        _TableField field = fieldList.get(0);
        sql.append(field.getColumn()).append("=#").append(field.getColumn()).append("#");
        //后面的加逗号
        for (int i=1;i<fieldList.size();i++)
        {
            field = fieldList.get(i);
            sql.append(", ").append(field.getColumn()).append("=#").append(field.getColumn()).append("#");
        }
        
        //where
        List<String> keyList = _table.getKeyList();
        //第一个不加 where
        StringBuilder where = new StringBuilder();
        where.append(" where ").append(keyList.get(0)).append("=#").append(keyList.get(0)).append("#");
        //后面的加 and
        for (int i=1;i<keyList.size();i++)
        {
            where.append(" and ").append(keyList.get(i)).append("=#").append(keyList.get(i)).append("#");
        }
        sql.append(where);
        
        int ret = 0;
        try
        {//执行SQL
            ret = zSQL.executeUpdate(sql.toString(), data, replaceMap);
        }
        catch (TableNotExistException e) 
        {//表不存在重作一次（可能被管理员删除，对误操作增加的保险机制）
            zTabler.create(_table, replaceMap, true);
            ret = zSQL.executeUpdate(sql.toString(), data, replaceMap);
        }
        
        if (ret > 0 && server.isCache(cls))
        {//更新缓存
            cache(cls);
        }
        
        return ret;
    }
    
    /********************************************************************************************/
    //delete 删除数据
    /********************************************************************************************/
    
    /**
     * 删除数据，多个主键时使用
     * 
     * @param cls           表类
     * @param ids           关键属性为数组，多个主键
     * @return              返回删除数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int delete(Class<?> cls, Object... ids) throws ORMException, SQLException
    {
        return delete(cls, null, ids);
    }
    
    /**
     * 删除数据，多个主键时使用
     * 
     * @param cls           表类
     * @param replaceMap    替换表
     * @param ids           关键属性为数组，多个主键
     * @return              返回删除数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int delete(Class<?> cls, MapSS replaceMap, Object... ids) throws ORMException, SQLException
    {
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[delete]["+cls.getName()+"][未找到相应的配置]");
        
        int ret = zTabler.delete(_table, replaceMap, ids);
        if (ret > 0 && server.isCache(cls))
        {//更新缓存
            cache(cls);
        }
        
        return ret;
    }
    
    /**
     * 删除数据, 根据条件
     * 
     * @param cls           表类
     * @param selector      对象选择器
     * @return              返回删除数
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int delete(Class<?> cls, Selector selector) throws ORMException, SQLException
    {
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[delete]["+cls.getName()+"][未找到相应的配置]");

        String result = _table.isValidSelector(selector);
        if (result != null)
            throw new ORMException("ZTable[delete]["+cls.getName()+"][查询器字段["+result+"]类型和值要求不一致]");
        
        int ret = zTabler.delete(_table, selector);
        if (ret > 0 && server.isCache(cls))
        {//更新缓存
            cache(cls);
        }
        
        return ret;
    }
    
    /**
     * 批量删除数据，根据主键删除
     * 
     * @param cls           表名
     * @param idsList       关键属性为数组的列表，多个主键列表
     * @return              返回删除结果列表
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int[] deleteBatch(Class<?> cls, List<Object[]> idsList) throws ORMException, SQLException
    {
        return deleteBatch(cls, null, idsList);
    }
    
    /**
     * 批量删除数据，根据主键删除
     * 
     * @param cls           表名
     * @param replaceMap    替换表
     * @param idsList       关键属性为数组的列表，多个主键列表
     * @return              返回删除结果列表
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int[] deleteBatch(Class<?> cls, MapSS replaceMap, List<Object[]> idsList) throws ORMException, SQLException
    {
        if (idsList == null || idsList.isEmpty())
            return new int[0];
        
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[delete]["+cls.getName()+"][未找到相应的配置]");
        
        int[] ret = zTabler.deleteBatch(_table, replaceMap, idsList);
        
        if (server.isCache(cls) && hasDataUpdate(ret))
        {//更新缓存
            cache(cls);
        }
        
        return ret;
    }
    
    /********************************************************************************************/
    //count 查询数目
    /********************************************************************************************/
    
    /**
     * 查询数目，多个主键时使用
     * 
     * @param cls           表类
     * @param ids           关键属性值
     * @return              存在的数目
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int count(Class<?> cls, Object... ids) throws ORMException, SQLException
    {
        return zTabler.count(getTable(cls), ids);
    }

    /**
     * 查询数目，整表查询
     * 
     * @param cls           表类
     * @return              int 数目值
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int count(Class<?> cls) throws ORMException, SQLException
    {
        return zTabler.count(getTable(cls));
    }
    
    /**
     * 查询数目，根据条件、可替换表查询
     * 
     * @param cls           表类
     * @param selector      对象查询器
     * @return              int 数目值
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public int count(Class<?> cls, Selector selector)throws ORMException, SQLException
    {
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[count]["+cls.getName()+"][未找到相应的配置]");
        
        String result = _table.isValidSelector(selector);
        if (result != null)
            throw new ORMException("ZTable[count]["+cls.getName()+"][查询器字段["+result+"]类型和值要求不一致]");
        
        return zTabler.count(_table, selector);
    }
    
    /**
     * 分组查询数目，根据条件、可替换表和分组字段
     * 
     * @param cls           表类
     * @param selector      对象查询器
     * @return              列表
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public List<MapSO> countGroupBy(Class<?> cls, Selector selector) throws ORMException, SQLException
    {
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[countGroupBy]["+cls.getName()+"][未找到相应的配置]");
        
        String result = _table.isValidSelector(selector);
        if (result != null)
            throw new ORMException("ZTable[count]["+cls.getName()+"][查询器字段["+result+"]类型和值要求不一致]");
        
        return zTabler.countGroupBy(_table, selector);
    }
    
    /********************************************************************************************/
    //sum 计算总和
    /********************************************************************************************/
    
    /**
     * 计算总和
     * 
     * @param cls           表类
     * @param field         表字段
     * @return              计算总和
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public long sum(Class<?> cls, String field) throws ORMException, SQLException
    {
        return sum(cls, new Selector(), field);
    }
    
    /**
     * 计算总和
     * 
     * @param cls           表类
     * @param field         表字段
     * @param selector      对象查询器
     * @return              计算总和
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public long sum(Class<?> cls, Selector selector, String field) throws ORMException, SQLException
    {
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[sum]["+cls.getName()+"][未找到相应的配置]");
        
        String result = _table.isValidSelector(selector);
        if (result != null)
            throw new ORMException("ZTable[sum]["+cls.getName()+"][查询器字段["+result+"]类型和值要求不一致]");
        
        return zTabler.sum(_table, selector, field);
    }
    
    /**
     * 计算多个总和
     * 
     * @param cls           表类
     * @param fields        多个表字段
     * @param selector      对象查询器
     * @return              计算多个总和
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public long[] sum(Class<?> cls, Selector selector, String... fields) throws ORMException, SQLException
    {
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[sum]["+cls.getName()+"][未找到相应的配置]");
        
        String result = _table.isValidSelector(selector);
        if (result != null)
            throw new ORMException("ZTable[sum]["+cls.getName()+"][查询器字段["+result+"]类型和值要求不一致]");
        
        return zTabler.sum(_table, selector, fields);
    }
    
    /********************************************************************************************/
    //item 查询一条数据
    /********************************************************************************************/
    
    /**
     * 查询一个表对象，支持多个主键
     * 
     * @param cls           表类
     * @param ids           关键属性值
     * @return              返回表对象
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public <T> T item(Class<T> cls, Object... ids) throws ORMException, SQLException
    {
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[item]["+cls.getName()+"][未找到相应的配置]");
        ORM.as(_table.isValidKeyObj(ids)?null:"ZTable[item]["+cls.getName()+"]传参与主键要求不匹配]");
        
        //检查和尝试创建表
        zTabler.create(_table);
        
        if (server.isCache(cls))
        {//从缓存中查找
            return zCache.item(cls, ids);
        }
        
        StringBuilder sql = new StringBuilder("select * from ").append(_table.getTable());

        String[] keyArr = _table.getKeyArr();
        //第一个where
        sql.append(" where ").append(keyArr[0]).append("=?");
        //后面的and
        for (int i=1;i<keyArr.length;i++)
        {
            sql.append(" and ").append(keyArr[i]).append("=?");
        }
        
        try
        {//执行SQL
            List<T> list = zSQL.executeQuery(sql.toString(), cls, ids);
            return list.isEmpty()?null:list.get(0);
        }
        catch (TableNotExistException e) 
        {//表不存在重作一次（可能被管理员删除，对误操作增加的保险机制）
            zTabler.create(_table, true);
            List<T> list = zSQL.executeQuery(sql.toString(), cls, ids);
            return list.isEmpty()?null:list.get(0);
        }
    }
    
    /**
     * 查询一个表对象，并指定返回属性,查询第一行
     * 
     * @param cls           表类
     * @return              返回表对象
     * @throws ORMException 映射异常,如果传入的属性不在配置文件中则异常
     * @throws SQLException 数据库异常
     */
    public <T> T item(Class<T> cls) throws ORMException, SQLException
    {
        return item(cls, new Selector());
    }
    
    /**
     * 查询一个表对象，并指定返回属性,查询条件和排序条件
     * 
     * @param cls           表类
     * @param selector      对象查询器
     * @return              返回表对象
     * @throws ORMException 映射异常,如果传入的属性不在配置文件中则异常
     * @throws SQLException 数据库异常
     */
    public <T> T item(Class<T> cls, Selector selector) throws ORMException, SQLException
    {
        ORM.as(selector != null?null:"ZTable[item][selector不允许为null]");
        
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[item]["+cls.getName()+"][未找到相应的配置]");
        
        String field = _table.isValidSelector(selector);
        if (field != null)
            throw new ORMException("ZTable[item]["+cls.getName()+"][查询器字段["+field+"]类型和值要求不一致]");
        
        //检查和尝试创建表
        zTabler.create(_table, selector.getReplaceMap());
        
        if (server.isCache(cls))
        {//从缓存中查找
            return zCache.item(cls, selector);
        }
        
        //组装SQL
        MapSO paramMap = new HashMapSO();
        String fieldSQL = selector.getFieldSQL(_table);
        String whereSQL = selector.getWhereSQL(_table, paramMap);
        String orderbySQL = selector.getOrderbySQL(_table);
        String groupbySQL = selector.getGroupbySQL(_table);
        String sql = server.getPolicy().toItemSQL(fieldSQL, _table.getTable(), whereSQL, orderbySQL, groupbySQL);
        
        List<T> list = null;
        try
        {//执行SQL
            list = zSQL.executeQuery(sql, cls, paramMap, selector.getReplaceMap());
        }
        catch (TableNotExistException e) 
        {//表不存在重作一次（可能被管理员删除，对误操作增加的保险机制）
            zTabler.create(_table, selector.getReplaceMap(), true);
            list = zSQL.executeQuery(sql, cls, paramMap, selector.getReplaceMap());
        }
        
        if (list.isEmpty())
            return null;
        
        //检查可替换参数
        T item = list.get(0);
        _table.addReplaceToData(item, selector.getReplaceMap());
        return item;
    }

    /**************************************************************************/
    //list 查询列表
    /**************************************************************************/
    
    /**
     * 查询表对象列表，全表查询
     * 
     * @param cls           表类
     * @return              返回表对象列表
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public <T> List<T> list(Class<T> cls) throws ORMException, SQLException
    {
        return list(cls, new Selector());
    }
    
    /**
     * 查询表对象列表，并指定返回属性,查询条件和排序条件
     * 
     * @param cls           表类
     * @param selector      对象查询器
     * @return              返回表对象列表
     * @throws ORMException 映射异常,如果传入的属性不在配置文件中则异常
     * @throws SQLException 数据库异常
     */
    public <T> List<T> list(Class<T> cls, Selector selector) throws ORMException, SQLException
    {
        ORM.as(selector != null?null:"ZTable[list][selector不允许为null]");
        
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[list]["+cls.getName()+"][未找到相应的配置]");
        
        String result = _table.isValidSelector(selector);
        if (result != null)
            throw new ORMException("ZTable[list]["+cls.getName()+"][查询器字段["+result+"]类型和值要求不一致]");
        
        //创建表当不存在时
        zTabler.create(_table, selector.getReplaceMap());
        
        if (server.isCache(cls))
        {//从缓存中查找
            return zCache.list(cls, selector);
        }
        
        //组装SQL
        MapSO paramMap = new HashMapSO();
        String fieldSQL = selector.getFieldSQL(_table);
        String whereSQL = selector.getWhereSQL(_table, paramMap);
        String orderbySQL = selector.getOrderbySQL(_table);
        String groupbySQL = selector.getGroupbySQL(_table);
        StringBuilder sql = new StringBuilder("select ").append(fieldSQL).append(" from ").append(_table.getTable()).append(whereSQL).append(orderbySQL).append(groupbySQL);
        
        List<T> list = null;
        try
        {//执行SQL
            list = zSQL.executeQuery(sql.toString(), cls, paramMap, selector.getReplaceMap());
        }
        catch (TableNotExistException e) 
        {//表不存在重作一次（可能被管理员删除，对误操作增加的保险机制）
            zTabler.create(_table, selector.getReplaceMap(), true);
            list = zSQL.executeQuery(sql.toString(), cls, paramMap, selector.getReplaceMap());
        }
        
        //检查有没有可替换参数
        for (T item : list)
        {
            _table.addReplaceToData(item, selector.getReplaceMap());
        }
        return list;
    }
    
    /**
     * 查询表对象列表，全表查询指定位置的数据
     * 
     * @param cls           表类
     * @param pageNo        页码
     * @param pageSize      页数
     * @return              返回表对象列表
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public <T> List<T> list(Class<T> cls, int pageNo, int pageSize) throws ORMException, SQLException
    {
        return list(cls, pageNo, pageSize, new Selector());
    }
    
    /**
     * 查询表对象列表，并指定位置,查询条件和排序条件
     * 
     * @param cls           表类
     * @param pageNo        页码
     * @param pageSize      页数
     * @param selector      对象查询器
     * @return              返回表对象列表
     * @throws ORMException 映射异常,如果传入的属性不在配置文件中则异常
     * @throws SQLException 数据库异常
     */
    public <T> List<T> list(Class<T> cls, int pageNo, int pageSize, Selector selector) throws ORMException, SQLException
    {
        ORM.as(selector != null?null:"ZTable[list][selector不允许为null]");
        
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[list]["+cls.getName()+"][未找到相应的配置]");

        String result = _table.isValidSelector(selector);
        if (result != null)
            throw new ORMException("ZTable[list]["+cls.getName()+"][查询器字段["+result+"]类型和值要求不一致]");
        
        //创建表当不存在时
        zTabler.create(_table, selector.getReplaceMap());
        
        if (server.isCache(cls))
        {//从缓存中查找
            return zCache.list(cls, pageNo, pageSize, selector);
        }
        
        //检查页码最小值和页大小有效性
        pageNo = (pageNo < 1)?1:pageNo;
        pageSize = (pageSize < 1)?10:pageSize;
        
        //执行SQL
        return list(_table, cls, pageNo, pageSize, selector);
    }
    
    /**************************************************************************/
    //page 分页显示
    /**************************************************************************/
    
    /**
     * 查询表对象分页信息
     * 
     * @param cls           表类
     * @param pageNo        页码
     * @param pageSize      页数
     * @return              分页信息,包括总页数,页码,页数和查询的记录
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public <T> PageResult<T> page(Class<T> cls, int pageNo, int pageSize) throws ORMException, SQLException
    {
        return page(cls, pageNo, pageSize, new Selector());
    }

    /**
     * 查询表对象分页信息
     * 
     * @param cls           表类
     * @param pageNo        页码
     * @param pageSize      页数
     * @param selector      对象查询器
     * @return              分页信息,包括总页数,页码,页数和查询的记录
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public <T> PageResult<T> page(Class<T> cls, int pageNo, int pageSize, Selector selector) throws ORMException, SQLException
    {
        ORM.as(selector != null?null:"ZTable[page][selector不允许为null]");
        
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[page]["+cls.getName()+"][未找到相应的配置]");

        String result = _table.isValidSelector(selector);
        if (result != null)
            throw new ORMException("ZTable[page]["+cls.getName()+"][查询器字段["+result+"]类型和值要求不一致]");
        
        //创建表当不存在时
        zTabler.create(_table, selector.getReplaceMap());
        
        if (server.isCache(cls))
        {//从缓存中查找
            return zCache.page(cls, pageNo, pageSize, selector);
        }
        
        //检查页码最小值和页大小有效性
        pageNo = (pageNo < 1)?1:pageNo;
        pageSize = (pageSize < 1)?10:pageSize;
        
        int total = count(cls, selector);
        if (total == 0)
            return PageBuilder.newResult(pageNo, pageSize);
        
        //检查页码最大值有效性
        int pageMax = (total-1) / pageSize + 1;
        pageNo = (pageNo > pageMax)?pageMax:pageNo;
        
        //执行SQL
        List<T> list = list(_table, cls, pageNo, pageSize, selector);
        return PageBuilder.newResult(total, pageNo, pageSize, list);
    }
    
    /**
     * 查询表对象分页信息
     * 
     * @param cls           表类
     * @param pageNo        页码
     * @param pageSize      页数
     * @param total         指定总数，不作count
     * @return              分页信息,包括总页数,页码,页数和查询的记录
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public <T> PageResult<T> page(Class<T> cls, int pageNo, int pageSize, int total) throws ORMException, SQLException
    {
        return page(cls, pageNo, pageSize, total, new Selector());
    }
    
    /**
     * 查询表对象分页信息
     * 
     * @param cls           表类
     * @param pageNo        页码
     * @param pageSize      页数
     * @param selector      对象查询器
     * @param total         指定总数，不作count
     * @return              分页信息,包括总页数,页码,页数和查询的记录
     * @throws ORMException 映射异常
     * @throws SQLException 数据库异常
     */
    public <T> PageResult<T> page(Class<T> cls, int pageNo, int pageSize, int total, Selector selector) throws ORMException, SQLException
    {
        ORM.as(selector != null?null:"ZTable[page][selector不允许为null]");
        
        _Table _table = getTable(cls);
        ORM.as(_table != null?null:"ZTable[page]["+cls.getName()+"][未找到相应的配置]");

        String result = _table.isValidSelector(selector);
        if (result != null)
            throw new ORMException("ZTable[page]["+cls.getName()+"][查询器字段["+result+"]类型和值要求不一致]");
        
        //创建表当不存在时
        zTabler.create(_table, selector.getReplaceMap());
        
        if (server.isCache(cls))
        {//从缓存中查找
            return zCache.page(cls, pageNo, pageSize, selector);
        }
        
        //检查页码最小值和页大小有效性
        pageNo = (pageNo < 1)?1:pageNo;
        pageSize = (pageSize < 1)?10:pageSize;
        
        //检查页码最大值有效性
        int pageMax = (total-1) / pageSize + 1;
        pageNo = (pageNo > pageMax)?pageMax:pageNo;
        
        //执行SQL
        List<T> list = list(_table, cls, pageNo, pageSize, selector);
        return PageBuilder.newResult(total, pageNo, pageSize, list);
    }
    
    /**************************************************************************/
    //内部方法
    /**************************************************************************/
    
    /** 
     * 内部方法，组装插入替换SQL 
     * 1.insert & insertOrUpdate & insertBatch
     * 2.replace & replaceBatch
     * 调用 
     */
    private String toInsertOrUpdateSQL(_Table _table, Object data, MapSO paramMap) throws ORMException
    {
        Class<?> clazz = data.getClass();
        Dbo dbo = server.getDbo(clazz);
        
        //组装SQL
        StringBuilder sql = new StringBuilder("insert into ").append(_table.getTable()).append("(");
        StringBuilder values = new StringBuilder("values (");
        List<_TableField> fieldList = _table.getFieldList();
        for (_TableField field : fieldList)
        {
            String fieldName = field.getField();
            String method = dbo.getGetMethod(fieldName);
            if (method == null)
                throw new ORMException("_Table/_View/_Dbo["+clazz.getName()+"]没有找到"+fieldName+"对应的方法]");
            
            try
            {//取值放置到MAP中，以fieldName方式
                Method m = clazz.getMethod(method, new Class[0]);
                Object value = m.invoke(data, new Object[0]);
                paramMap.put(fieldName, value);
                sql.append(field.getColumn()).append(",");
                values.append("#").append(fieldName).append("#").append(",");
            }
            catch (Exception e)
            {
                throw new ORMException(e);
            }
        }
        
        //去除最后一个逗号
        sql.setLength(sql.length()-1);
        values.setLength(values.length()-1);
        
        //最后加结尾
        sql.append(") ").append(values).append(")");
        
        return sql.toString();
    }
    
    /** 内部方法，list & page 调用 */
    private <T> List<T> list(_Table _table, Class<T> cls, int pageNo, int pageSize, Selector selector) throws ORMException, SQLException
    {
        int minNum = (pageNo-1) * pageSize + 1;
        int maxNum = pageNo * pageSize;
        
        MapSO paramMap = new HashMapSO();
        paramMap.put("minNum", minNum);
        paramMap.put("maxNum", maxNum);
        paramMap.put("minSize", minNum - 1);
        paramMap.put("pageSize", pageSize);
        
        //组装SQL
        String fieldSQL = selector.getFieldSQL(_table);
        String whereSQL = selector.getWhereSQL(_table, paramMap);
        String orderbySQL = selector.getOrderbySQL(_table);
        String groupbySQL = selector.getGroupbySQL(_table);
        String sql = server.getPolicy().toPageSQL(fieldSQL, _table.getTable(), whereSQL, orderbySQL, groupbySQL, maxNum, pageNo);
        
        List<T> list = null;
        try
        {//执行SQL
            list = zSQL.executeQuery(sql, cls, paramMap, selector.getReplaceMap());
        }
        catch (TableNotExistException e) 
        {//表不存在重作一次（可能被管理员删除，对误操作增加的保险机制）
            zTabler.create(_table, selector.getReplaceMap(), true);
            list = zSQL.executeQuery(sql, cls, paramMap, selector.getReplaceMap());
        }
        
        //检查有没有可替换参数
        for (T item : list)
        {
            _table.addReplaceToData(item, selector.getReplaceMap());
        }
        return list;
    }
    
    /** 是否有数据更新 */
    private boolean hasDataUpdate(int[] rets)
    {
        for (int ret : rets)
        {
            if (ret > 0)
                return true;
        }
        
        return false;
    }
}
